<?php
/**
 * Copyright (c) [2019] [吴跃忠]
 * [selibra] is licensed under the Mulan PSL v1.
 * You can use this software according to the terms and conditions of the Mulan PSL v1.
 * You may obtain a copy of Mulan PSL v1 at:
 * http://license.coscl.org.cn/MulanPSL
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
 * PURPOSE.
 * See the Mulan PSL v1 for more details.
 */

namespace Selibra\WebSocket;


use Selibra\Di\Annotations\Autowired;
use Selibra\Di\DI;
use Selibra\WebSocket\Exceptions\ActionNotFoundException;
use Selibra\WebSocket\Interceptor\ActionSpaceInterceptorCollector;
use Selibra\WebSocket\Interceptor\ActionSpaceNode;
use Selibra\WebSocket\Protocols\WebSocketActionDispatcherInterface;

/**
 * WebSocket指令调度器
 * Class WSActionDispatcher
 * @package Selibra\WebSocket
 */
class WSActionDispatcher implements WebSocketActionDispatcherInterface
{

    /**
     * @var ActionCollector
     */
    #[Autowired]
    protected ActionCollector $actionCollector;

    /**
     * @var ActionContainer
     */
    #[Autowired]
    protected ActionContainer $actionContainer;


    /**
     * @param Message $message
     * @return mixed|void
     * @throws ActionNotFoundException
     */
    public function run(Message $message)
    {
        $action = $message->getMessageInput()->getAction();
        $actionData = $this->actionCollector->get($action);
        if (empty($actionData)) {
            throw new ActionNotFoundException();
        }
        $actionClassName = $actionData['namespace'];
        $actionMethodName = $actionData['method'];

        /** @var object $actionClass */
        $actionClass = $this->actionContainer->get($actionClassName);
        if (!empty($actionClass)) {
            // 执行前置操作
            $this->before($message);
            $actionClass->$actionMethodName($message);
            $this->after();
        } else {
            throw new ActionNotFoundException();
        }
    }


    /**
     * @param $message
     */
    public function before(Message $message)
    {
        /** @var ActionSpaceNode[] $interceptors */
        $interceptors = ActionSpaceInterceptorCollector::getInterceptors($message->getMessageInput()->getAction());
        foreach ($interceptors as $interceptor) {
            $namespace = $interceptor->getNamespace();
            $method = $interceptor->getMethod();
            $interceptorInt = DI::getObjectContext($namespace);
            if( !empty($interceptorInt) ){
                $interceptorInt->$method($message);
            }
        }
    }


    public function after()
    {

    }
}